/*
 * Author: nicolas.bredeche(@)lri.fr
 * Created on 14 janv. 2006
 * 
 */

package picoevo.ext.evolution;

import picoevo.core.evolution.SelectionOperator;
import picoevo.core.representation.Individual;
import picoevo.core.representation.Population;
import picoevo.core.representation.PopulationContainer;
import picoevo.core.representation.PopulationObject;
import picoevo.core.representation.PopulationView;
import picoevo.gp.evolution.VariationOperator_Population_TreeGP_CrossOver;

// DO NOT USE
// DO NOT USE
// DO NOT USE
// DO NOT USE
// DO NOT USE

public class SelectionOperator_ProgressiveVariation extends SelectionOperator {

	public SelectionOperator_ProgressiveVariation() {
		super("MuLambda selection operator");
	}

	public SelectionOperator_ProgressiveVariation(String __name) {
		super(__name);
	}

	/**
	 * ### UNDER DEVELOPMENT -- BETA VERSION ### written by nicolas (20060327)
	 * 
	 * The "progressive variation" selection operator variates candidates
	 * according to their performance - the worst is the best candidate for
	 * variation. The progressive variation acts as a pre-filter prior to
	 * standard variation operators. The main property of this selection
	 * operator is that it is index conservative - which is particularly handy
	 * when individuals are to be tracked during the course of evolution -- for
	 * example when co-evolving two populations where the first population
	 * representation includes pointer towards individuals in the second
	 * population (see the coEvoModuleForSymReg package)
	 * 
	 * This selection operator performs :
	 * 
	 * strategy 1 (IMPLEMENTED) 1. variate the N (ordered) individuals with
	 * probability (1-rank/N*f(rank)) with f(0...N-1)->[0...1], default is f=1
	 * 2. if variation is true, apply rank-independant op(s) note 1 : a f(rank)
	 * can be defined so as to conserve the N best individuals note 2 : possible
	 * step 2 variation operators may be : renewOp, cloneOp,
	 * crossover(parter:uniform;progressive;1/progressive...), mutate note 3 :
	 * 
	 * strategy 2 (NOT IMPLEMENTED) possibly less generic 1. copy of the N best
	 * individuals 2. mutate of the M second-to-best 3. renew the O worst with
	 * completely random individuals 4. renew the P second-to-worst with altered
	 * version of the N best (and optionaly, also with the M second-to-best)
	 * 
	 */
	@Override
	public void performSelection(PopulationObject __population) {
		Population pop = (Population) __population;

		PopulationContainer newPop = new PopulationContainer(SelectionOperator_GetView.performSelectionView(pop)); // newpop
		// is
		// unordered
		// -
		// i.e.
		// ensures
		// variations
		// conservative
		// index
		PopulationView popOrderedView = SelectionOperator_SimpleRank.performSelectionView(newPop); // return
		// an
		// ordered
		// list
		// -
		// useful
		// for
		// "progressive
		// variation"

		int popsize = pop.getPopulationSize();
		for (int j = 0; j != popsize; j++) // successively consider every
		// candidate for variation
		{
			if (isVariate(j, popsize) == true) {
				// Display.debug("muteModule?");
				// apply variation operators.
				// individual-level variation operator(s) (here: only mutation)
				// (popOrderedView.getIndividual(j)).performVariations();
				// if ( Math.random() <
				// ((ParameterSet_Evolution_mulambdaES)pop.getTemplate()).getMutationRate()
				// )
				// {
				// Display.debug("muteModule");

				// * may perform 2-individual crossover variation
				if ((pop.getTemplate()).getDoubleProperty("CrossoverRate") < Math.random()) {
					VariationOperator_Population_TreeGP_CrossOver op = new VariationOperator_Population_TreeGP_CrossOver("tempCrossOverOp"); // TODO
					// -
					// optimise!!!
					double partnerIndex = Math.random();
					partnerIndex = (1.0 - (partnerIndex * partnerIndex)) * popsize; // favor
					// best
					// -
					// hack?
					// TODO
					// -
					// replace
					// with
					// clever
					// ponderation
					op.performCrossOver((popOrderedView.getIndividual(j)), (Individual) ((popOrderedView.getIndividual((int) partnerIndex)).clone()), pop.getTemplate()); // clone
					// will
					// be
					// dumped
				}

				// * may perform individual-level variation
				(popOrderedView.getIndividual(j)).performVariations();

				// PopulationContainer popTarget = new PopulationContainer();
				// popTarget.registerIndividual(popOrderedView.getIndividual(j));
				// popTarget.addOperatorList(pop.getVariationOperatorList());
				// }
				/*
				 * if ( Math.random() <
				 * ((ParameterSet_Evolution_mulambdaES)pop.getTemplate()).getCrossoverRate() ) { //
				 * il y a surement des trucs a faire avant, comme le controle
				 * explicite du performVariation }
				 */
			}
		}

		pop.renewPopulation(newPop);
	}

	private static boolean isVariate(int index, int total) {
		// double unchangedNb = (double)total/10.0; // the best 10% are
		// unchanged
		double unchangedNb = total / 2.0; // the best 50% are
		// unchanged

		if (index > (int) unchangedNb) {
			if (Math.random() < (double) index / (double) total) // c'est ici
				// qu'on
				// ajoute la
				// fonction
				// de
				// ponderation
				// --
				// lineaire,
				// exp,
				// log...
				return true;
			else
				return false;
		} else
			return false;
	}

}
